﻿using EntityFrameworkCore.UseRowNumberForPaging;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.Loader;
using VOL.Core.Configuration;
using VOL.Core.Const;
using VOL.Core.DBManager;
using VOL.Core.Enums;
using VOL.Core.Extensions;
using VOL.Core.Extensions.AutofacManager;
using VOL.Entity.DomainModels;
using VOL.Entity.DomainModels.BasicData;
using VOL.Entity.DomainModels.DoctorManage;
using VOL.Entity.DomainModels.EquipmentManage;
using VOL.Entity.DomainModels.EvaluateNurseCare;
using VOL.Entity.DomainModels.HealthEducation;
using VOL.Entity.DomainModels.WorkforceManage;
using VOL.Entity.DrugViewing;
using VOL.Entity.SystemModels;

namespace VOL.Core.EFDbContext
{
    public class VOLContext : DbContext, IDependency
    {
        /// <summary>
        /// 数据库连接名称 
        /// </summary>
        public string DataBaseName = null;
        public VOLContext()
                : base()
        {
        }
        public VOLContext(string connction)
            : base()
        {
            DataBaseName = connction;
        }

        public VOLContext(DbContextOptions<VOLContext> options)
            : base(options)
        {

        }

        public DbSet<BroadCasLog> BroadCasLog { get; set; }

        /// <summary>
        /// 护理单元病房分配
        /// </summary>
        public DbSet<NursingUnitWardModel> NursingUnit { get; set; }

        public DbSet<ReplaceTableModel> ReplaceTable {  get; set; }

        public DbSet<PatientReCordModel> PatientReCord { get; set; }
        /// <summary>
        /// 替班申请程序集
        /// </summary>
        public DbSet<ReplaceWorkModel> ReplaceWork { get; set; }
     
        /// <summary>
        /// 健康宣教
        /// </summary>
        public DbSet<BroadCastTemplate> BroadCastTemplate { get; set; }
        /// <summary>
        /// 广播类型
        /// </summary>
        public DbSet<BroadType> BroadType { get; set; }
        /// <summary>
        /// 广播管理
        /// </summary>
        public DbSet<BroadCastManage> BroadCastManage { get; set; }
        /// <summary>
        /// 排班管理程序集
        /// </summary>
        public DbSet<WorkforceModel> Workforce { get; set; }
        /// <summary>
        /// 护士程序集
        /// </summary>
        public DbSet<Nurse> Nurse { get; set; }
        public DbSet<EquipmentRecord> EquipmentRecord { get; set; }

        public DbSet<ClassBedManageModel> ClassBedManage { get; set; }

        public DbSet<NurseGroupModel> NurseGroup { get; set; }

        public DbSet<DoctorModel> Doctor { get; set; }

        public DbSet<TellModel> Tell { get; set; }

        public DbSet<WardArea> WardArea {  get; set; }

        /// <summary>
        /// 病房
        /// </summary>
        public DbSet<WardModel> Ward {  get; set; }
        /// <summary>
        /// 科室程序集
        /// </summary>
        public DbSet<OfficeModel> Office { get; set; }
        /// <summary>
        /// 病区病房关联程序集
        /// </summary>
        public DbSet<WardAreaHouseModel> WardAreaHouse { get; set; }
        /// <summary>
        /// 广播内容程序集
        /// </summary>
        public DbSet<BroadCastModel> BroadCast { get; set; }
        /// <summary>
        /// 药品管理
        /// </summary>
        public DbSet<DrugViewingModel> DrugViewing {  get; set; }

        public override void Dispose()
        {
            base.Dispose();
        }


        public DbSet<Entity.DomainModels.Porter> Porter { get; set; }

        public DbSet<Entity.DomainModels.PorterWardArea> PorterWardArea { get; set; }
        
        public DbSet<Entity.DomainModels.Bed> Bed { get; set; }
        public DbSet<Entity.DomainModels.PorterWorkDetail> PorterWorkDetail { get; set; }
        public DbSet<Entity.DomainModels.Patient> Patient { get; set; }
        public DbSet<Entity.DomainModels.Equipment> Equipment { get; set; }
        public DbSet<Entity.DomainModels.InAssess> InAssess { get; set; }


        public override int SaveChanges()
        {
            try
            {
                return base.SaveChanges();
            }
            catch (Exception ex)//DbUpdateException 
            {
                throw (ex.InnerException as Exception ?? ex);
            }
        }
        public override DbSet<TEntity> Set<TEntity>()
        {
            return base.Set<TEntity>();
        }
        //public DbSet<TEntity> Set<TEntity>(bool trackAll = false) where TEntity : class
        //{
        //    return base.Set<TEntity>();
        //}
        /// <summary>
        /// 设置跟踪状态
        /// </summary>
        public bool QueryTracking
        {
            set
            {
                this.ChangeTracker.QueryTrackingBehavior =
                       value ? QueryTrackingBehavior.TrackAll
                       : QueryTrackingBehavior.NoTracking;
            }
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (optionsBuilder.IsConfigured)
            {
                return;
            }
            string connectionString = DBServerProvider.GetConnectionString(null);
            if (Const.DBType.Name == Enums.DbCurrentType.MySql.ToString())
            {
                optionsBuilder.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 11)));
            }
            else if (Const.DBType.Name == Enums.DbCurrentType.PgSql.ToString())
            {
                optionsBuilder.UseNpgsql(connectionString);
            }
            else if (Const.DBType.Name == Enums.DbCurrentType.DM.ToString())
            {
                //optionsBuilder.UseDm(connectionString);
            }
            else if (Const.DBType.Name == Enums.DbCurrentType.Oracle.ToString())
            {
                optionsBuilder.UseOracle(connectionString, x => x.UseOracleSQLCompatibility(OracleSQLCompatibility.DatabaseVersion19));
                // optionsBuilder.UseOracle(connectionString, b => b.UseOracleSQLCompatibility("11"));
            }
            else
            {
                if (AppSetting.GetSettingString("UseSqlserver2008") == "1")
                {
                    optionsBuilder.UseSqlServer(connectionString, x => x.UseRowNumberForPaging());
                }
                optionsBuilder.UseSqlServer(connectionString, o => o.UseCompatibilityLevel(120));
            }
            //默认禁用实体跟踪
            optionsBuilder = optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
            // optionsBuilder.AddInterceptors(new SqlCommandInterceptor());
            base.OnConfiguring(optionsBuilder);
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            Type type = null;
            try
            {
                //获取所有类库
                var compilationLibrary = DependencyContext
                    .Default
                    .RuntimeLibraries
                    .Where(x => !x.Serviceable && x.Type != "package" && x.Type == "project");
                foreach (var _compilation in compilationLibrary)
                {
                    //加载指定类
                    AssemblyLoadContext.Default
                    .LoadFromAssemblyName(new AssemblyName(_compilation.Name))
                    .GetTypes()
                    .Where(x =>
                        x.GetTypeInfo().BaseType != null
                        && x.BaseType == (typeof(BaseEntity)))
                        .ToList().ForEach(t =>
                        {
                            modelBuilder.Entity(t);
                            //  modelBuilder.Model.AddEntityType(t);
                        });
                }

                //Oracle数据库指定表名与列名全部大写
                if (DBType.Name == DbCurrentType.Oracle.ToString())
                {
                    foreach (var entity in modelBuilder.Model.GetEntityTypes())
                    {
                        string tableName = entity.GetTableName().ToUpper();
                        // if (tableName.StartsWith("SYS_") || tableName.StartsWith("DEMO_"))
                        {
                            entity.SetTableName(entity.GetTableName().ToUpper());
                            foreach (var property in entity.GetProperties())
                            {
                                property.SetColumnName(property.Name.ToUpper());
                                if (property.ClrType == typeof(Guid))
                                {
                                    property.SetValueConverter(new ValueConverter<Guid, string>(v => v.ToString(), v => new Guid(v)));
                                }
                                else if (property.ClrType == typeof(Guid?))
                                {
                                    property.SetValueConverter(new ValueConverter<Guid?, string>(v => v.ToString(), v => new Guid(v)));
                                }
                            }
                        }
                    }
                }

                //modelBuilder.AddEntityConfigurationsFromAssembly(GetType().Assembly);
                base.OnModelCreating(modelBuilder);
            }
            catch (Exception ex)
            {
                string mapPath = ($"Log/").MapPath();
                Utilities.FileHelper.WriteFile(mapPath,
                    $"syslog_{DateTime.Now.ToString("yyyyMMddHHmmss")}.txt",
                    type?.Name + "--------" + ex.Message + ex.StackTrace + ex.Source);
            }

        }
    }
}
 